﻿
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.IO;
using System;
using System.Text.RegularExpressions;
using System.Linq;

namespace BaseUtils.Utils
{
    /// <summary>
    /// JSON 文件属性操作工具类（.NET Framework 4.8 全版本兼容，支持注释/尾随逗号）
    /// </summary>
    public static class JsonHelper
    {
        /// <summary>
        /// 安全新增或更新JSON文件中的属性
        /// - 若目标属性不存在：在指定路径的父对象下新增该属性
        /// - 若目标属性已存在：直接更新属性值
        /// </summary>
        /// <param name="jsonFilePath">JSON文件路径</param>
        /// <param name="fullPropPath">完整属性路径（例：$.app.user.email，email为要新增/更新的属性）</param>
        /// <param name="propValue">属性值（支持字符串、数值、布尔等基础类型）</param>
        /// <returns>结构化更新结果（含成功/失败提示）</returns>
        public static UpdateResult WriteValue(string jsonFilePath, string fullPropPath, object propValue)
        {
            // 步骤1：基础校验（文件路径、属性路径格式）
            var baseCheck = ValidateBaseInfo(jsonFilePath, fullPropPath);
            if (!baseCheck.IsSuccess)
            {
                return baseCheck;
            }

            // 步骤2：拆分“父对象路径”和“目标属性名”
            int lastDotIndex = fullPropPath.LastIndexOf('.');
            if (lastDotIndex < 1) // 至少需满足 $.父.子 格式（$.a.b 中 lastDotIndex > 2）
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = "属性路径格式错误：需包含父对象（例：$.app，不能是 $.）",
                    TargetPath = fullPropPath
                };
            }
            string parentPath = fullPropPath.Substring(0, lastDotIndex); // 父对象路径
            string targetPropName = fullPropPath.Substring(lastDotIndex + 1); // 目标属性名

            JToken rootNode = null;
            string oldValue = null;
            string newValueStr = JsonConvert.SerializeObject(propValue);

            try
            {
                // 步骤3：加载文件并解析（先清理注释和尾随逗号）
                var loadResult = LoadJsonWithCheck(jsonFilePath);
                if (!loadResult.IsSuccess)
                {
                    return new UpdateResult
                    {
                        IsSuccess = false,
                        Message = $"加载文件失败：{loadResult.Message}",
                        TargetPath = fullPropPath
                    };
                }
                rootNode = loadResult.RootNode;

                // 步骤4：定位父对象并校验
                var parentNode = rootNode.SelectToken(parentPath);
                if (parentNode == null)
                {
                    return new UpdateResult
                    {
                        IsSuccess = false,
                        Message = $"未找到父对象路径 -> {parentPath}",
                        TargetPath = fullPropPath
                    };
                }
                if (parentNode.Type != JTokenType.Object)
                {
                    return new UpdateResult
                    {
                        IsSuccess = false,
                        Message = $"父路径不是对象（无法新增属性）-> {parentPath}（当前类型：{GetNodeType(parentNode)}）",
                        TargetPath = fullPropPath
                    };
                }
                JObject parentObj = (JObject)parentNode;

                // 步骤5：检查目标属性是否已存在
                var existingPropNode = parentObj[targetPropName];
                if (existingPropNode != null)
                {
                    // 场景A：属性已存在 → 执行更新
                    oldValue = existingPropNode.ToString(Formatting.None);
                    if (!IsValueTypeMatch(existingPropNode, propValue))
                    {
                        return new UpdateResult
                        {
                            IsSuccess = false,
                            Message = $"属性类型不匹配（当前类型：{GetNodeType(existingPropNode)}，新值类型：{propValue.GetType().Name}）",
                            TargetPath = fullPropPath,
                            OldValue = oldValue,
                            NewValue = newValueStr
                        };
                    }
                    // 更新属性值
                    parentObj[targetPropName] = JToken.Parse(newValueStr);
                    return ExecuteSaveAndVerify(jsonFilePath, rootNode, fullPropPath, oldValue, newValueStr, "更新");
                }
                else
                {
                    // 场景B：属性不存在 → 执行新增
                    oldValue = "（属性不存在）";
                    // 将属性值转为JToken并添加到父对象
                    parentObj.Add(targetPropName, JToken.Parse(newValueStr));
                    return ExecuteSaveAndVerify(jsonFilePath, rootNode, fullPropPath, oldValue, newValueStr, "新增");
                }
            }
            catch (JsonReaderException ex)
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = $"JSON格式错误：{ex.Message}",
                    TargetPath = fullPropPath,
                    OldValue = oldValue,
                    NewValue = newValueStr
                };
            }
            catch (Exception ex)
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = $"新增/更新属性失败：{ex.Message}",
                    TargetPath = fullPropPath,
                    OldValue = oldValue,
                    NewValue = newValueStr
                };
            }
        }

        /// <summary>
        /// 验证JSON节点与新值的类型是否匹配
        /// </summary>
        private static bool IsValueTypeMatch(JToken node, object newValue)
        {
            // 处理空节点情况
            if (node == null)
                return newValue == null;

            switch (node.Type)
            {
                // 数值类型匹配：int/long/float/double/decimal
                case JTokenType.Integer:
                case JTokenType.Float:
                    return newValue is int
                        || newValue is long
                        || newValue is float
                        || newValue is double
                        || newValue is decimal;

                // 字符串类型匹配
                case JTokenType.String:
                    return newValue is string;

                // 布尔类型匹配
                case JTokenType.Boolean:
                    return newValue is bool;

                // Null类型匹配
                case JTokenType.Null:
                    return newValue == null;

                // 对象/数组不在这里校验
                default:
                    return false;
            }
        }

        /// <summary>
        /// 加载JSON文件并校验（先清理注释和尾随逗号，兼容所有Newtonsoft版本）
        /// </summary>
        private static (bool IsSuccess, JToken RootNode, string Message) LoadJsonWithCheck(string jsonFilePath)
        {
            try
            {
                // 校验文件是否可读
                if (!IsFileReadable(jsonFilePath))
                {
                    return (false, null, $"文件不可读（可能无权限或被占用）-> {jsonFilePath}");
                }

                // 读取文件内容
                string content = File.ReadAllText(jsonFilePath, System.Text.Encoding.UTF8);
                if (string.IsNullOrWhiteSpace(content))
                {
                    return (false, null, "文件内容为空，无法解析JSON");
                }

                // 核心修复：不依赖高版本属性，通过正则手动清理JSON（支持//注释、/*多行注释、尾随逗号）
                string cleanedJson = CleanJsonForCompatibility(content);

                // 基础解析（无需依赖高版本配置）
                // 初始化配置对象
                JsonLoadSettings settings = new JsonLoadSettings
                {
                    // 允许 JSON 中包含注释（// 或 /* */）
                    CommentHandling = CommentHandling.Ignore,

                    // 遇到重复的属性键时，忽略后续的键（默认会抛出异常）
                    DuplicatePropertyNameHandling = DuplicatePropertyNameHandling.Ignore,

                    // 解析错误时包含行号和位置信息（便于调试）
                    LineInfoHandling = LineInfoHandling.Load
                };

                // 修复后解析
                JToken rootNode = JToken.Parse(content);
                return (true, rootNode, "文件加载成功");
            }
            catch (JsonReaderException ex)
            {
                return (false, null, $"JSON格式错误 -> {ex.Message}");
            }
            catch (Exception ex)
            {
                return (false, null, $"加载文件失败 -> {ex.Message}");
            }
        }

        /// <summary>
        /// 清理JSON中的注释和尾随逗号（兼容低版本Newtonsoft）
        /// </summary>
        private static string CleanJsonForCompatibility(string json)
        {
            if (string.IsNullOrEmpty(json))
                return json;

            // 1. 移除单行注释（// 到行尾）
            json = Regex.Replace(json, @"//.*(?=\r?\n|$)", "", RegexOptions.Multiline);

            // 2. 移除多行注释（/* 到 */，支持跨多行）
            json = Regex.Replace(json, @"/\*.*?\*/", "", RegexOptions.Singleline);

            // 3. 移除对象/数组末尾的尾随逗号（如 { "a":1, } 或 [1,2, ]）
            // 匹配规则：逗号 + 空白字符 + } 或 ]
            json = Regex.Replace(json, @",\s*(?=[}\]])", "", RegexOptions.Multiline);

            return json;
        }

        /// <summary>
        /// 基础信息校验（文件路径、目标路径格式）
        /// </summary>
        private static UpdateResult ValidateBaseInfo(string jsonFilePath, string targetPath)
        {
            // 校验文件路径
            if (string.IsNullOrWhiteSpace(jsonFilePath))
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = "基础校验失败：JSON文件路径不能为空",
                    TargetPath = targetPath
                };
            }
            if (!File.Exists(jsonFilePath))
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = $"基础校验失败：文件不存在 -> {jsonFilePath}",
                    TargetPath = targetPath
                };
            }
            // 校验目标路径格式（必须以 $. 开头，符合JSON Path规范）
            if (string.IsNullOrWhiteSpace(targetPath) || !targetPath.StartsWith("$.", StringComparison.Ordinal))
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = $"基础校验失败：目标路径格式错误（需以 $. 开头，例：$.app.user）",
                    TargetPath = targetPath
                };
            }
            return new UpdateResult { IsSuccess = true };
        }

        /// <summary>
        /// 获取节点的具体类型（用于错误提示）
        /// </summary>
        private static string GetNodeType(JToken node)
        {
            if (node == null)
                return "Null";

            switch (node.Type)
            {
                case JTokenType.Object:
                    return "Object（对象）";
                case JTokenType.Array:
                    return "Array（数组）";
                case JTokenType.Integer:
                case JTokenType.Float:
                    return "Number（数值）";
                case JTokenType.String:
                    return "String（字符串）";
                case JTokenType.Boolean:
                    return "Boolean（布尔）";
                case JTokenType.Null:
                    return "Null";
                default:
                    return "Unknown（未知）";
            }
        }

        /// <summary>
        /// 复用保存和校验逻辑（减少代码重复）
        /// </summary>
        private static UpdateResult ExecuteSaveAndVerify(string jsonFilePath, JToken rootNode, string targetPath, string oldValue, string newValueStr, string actionType)
        {
            // 保存文件
            var saveResult = SaveJsonWithCheck(jsonFilePath, rootNode);
            if (!saveResult.IsSuccess)
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = $"{actionType}失败：{saveResult.Message}",
                    TargetPath = targetPath,
                    OldValue = oldValue,
                    NewValue = newValueStr
                };
            }

            // 校验结果
            var verifyResult = VerifyFileAfterUpdate(jsonFilePath, targetPath, newValueStr);
            if (!verifyResult.IsSuccess)
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = $"{actionType}失败：{verifyResult.Message}",
                    TargetPath = targetPath,
                    OldValue = oldValue,
                    NewValue = newValueStr
                };
            }

            // 成功返回
            return new UpdateResult
            {
                IsSuccess = true,
                Message = $"{actionType}成功：属性已{actionType}并保存",
                TargetPath = targetPath,
                OldValue = oldValue,
                NewValue = newValueStr
            };
        }

        /// <summary>
        /// 保存JSON文件并校验（写入权限、文件完整性）
        /// </summary>
        private static (bool IsSuccess, string Message) SaveJsonWithCheck(string jsonFilePath, JToken rootNode)
        {
            try
            {
                // 校验文件是否可写
                if (!IsFileWritable(jsonFilePath))
                {
                    return (false, $"文件不可写（可能无权限或被占用）-> {jsonFilePath}");
                }

                // 生成格式化JSON（仅用基础属性，兼容低版本）
                var serializerSettings = new JsonSerializerSettings
                {
                    Formatting = Formatting.Indented, // 缩进格式化（基础属性，全版本支持）
                    StringEscapeHandling = StringEscapeHandling.Default, // 中文不转义（基础属性）
                    MaxDepth = 64
                };
                using (var stringWriter = new StringWriter())
                {
                    JsonSerializer.Create(serializerSettings).Serialize(stringWriter, rootNode);
                    string updatedContent = stringWriter.ToString();

                    // 写入临时文件（避免原文件损坏）
                    string tempFilePath = $"{jsonFilePath}.tmp";
                    File.WriteAllText(tempFilePath, updatedContent, System.Text.Encoding.UTF8);

                    // 校验临时文件有效性
                    if (!File.Exists(tempFilePath) || new FileInfo(tempFilePath).Length == 0)
                    {
                        File.Delete(tempFilePath); // 清理无效临时文件
                        return (false, "临时文件写入失败，更新终止（避免原文件损坏）");
                    }

                    // 替换原文件（原子操作思路）
                    if (File.Exists(jsonFilePath))
                    {
                        File.Delete(jsonFilePath);
                    }
                    File.Move(tempFilePath, jsonFilePath);

                    return (true, "文件保存成功");
                }
            }
            catch (Exception ex)
            {
                // 异常时清理临时文件
                string tempFilePath = $"{jsonFilePath}.tmp";
                if (File.Exists(tempFilePath))
                {
                    File.Delete(tempFilePath);
                }
                return (false, $"保存文件失败 -> {ex.Message}");
            }
        }

        /// <summary>
        /// 更新后校验（重新读取文件，确认目标值已更新）
        /// </summary>
        private static (bool IsSuccess, string Message) VerifyFileAfterUpdate(string jsonFilePath, string targetPath, string expectedValue)
        {
            try
            {
                // 重新加载文件（复用清理逻辑）
                var loadResult = LoadJsonWithCheck(jsonFilePath);
                if (!loadResult.IsSuccess)
                {
                    return (false, $"重新加载文件失败：{loadResult.Message}");
                }

                // 定位目标节点并校验值
                var targetNode = loadResult.RootNode.SelectToken(targetPath);
                if (targetNode == null)
                {
                    return (false, "更新后未找到目标路径（可能节点被误删）");
                }

                string actualValue = targetNode.ToString(Formatting.None);
                if (!actualValue.Equals(expectedValue, StringComparison.Ordinal))
                {
                    string expectedPreview = expectedValue.Length > 50 ? $"{expectedValue.Substring(0, 50)}..." : expectedValue;
                    string actualPreview = actualValue.Length > 50 ? $"{actualValue.Substring(0, 50)}..." : actualValue;
                    return (false, $"更新后值不匹配（预期：{expectedPreview}，实际：{actualPreview}）");
                }

                return (true, "更新后文件校验通过");
            }
            catch (Exception ex)
            {
                return (false, $"校验更新结果失败 -> {ex.Message}");
            }
        }

        /// <summary>
        /// 检查文件是否可读
        /// </summary>
        private static bool IsFileReadable(string filePath)
        {
            if (!File.Exists(filePath))
                return false;

            try
            {
                using (FileStream stream = File.OpenRead(filePath))
                {
                    return true;
                }
            }
            catch
            {
                return false;
            }
        }
        private static bool IsFileWritable(string filePath)
        {
            // 文件存在：尝试打开写入流校验
            if (File.Exists(filePath))
            {
                try
                {
                    using (FileStream stream = File.OpenWrite(filePath))
                    {
                        return true;
                    }
                }
                catch
                {
                    return false;
                }
            }
            // 文件不存在：校验所在目录是否可写
            else
            {
                string directory = Path.GetDirectoryName(filePath);
                if (string.IsNullOrWhiteSpace(directory))
                    directory = Environment.CurrentDirectory;

                try
                {
                    string testFilePath = Path.Combine(directory, "temp_write_test.tmp");
                    File.WriteAllText(testFilePath, "test", System.Text.Encoding.UTF8);
                    File.Delete(testFilePath);
                    return true;
                }
                catch
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// 安全删除JSON文件中的指定节点（支持根节点/嵌套节点）
        /// - 若节点存在：删除节点并保存文件
        /// - 若节点不存在：返回提示信息（不修改文件）
        /// </summary>
        /// <param name="jsonFilePath">JSON文件路径</param>
        /// <param name="fullNodePath">完整节点路径（例：$.namedsfsff 或 $.processors[0].name，遵循JSON Path规范）</param>
        /// <returns>结构化删除结果（含成功/失败提示、删除前的值）</returns>
        public static UpdateResult DeleteNode(string jsonFilePath, string fullNodePath)
        {
            // 步骤1：基础校验（复用原校验逻辑，确保一致性）
            var baseCheck = ValidateBaseInfo(jsonFilePath, fullNodePath);
            if (!baseCheck.IsSuccess)
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = baseCheck.Message,
                    TargetPath = fullNodePath
                };
            }

            JToken rootNode = null;
            string deletedValue = "（节点不存在）";

            try
            {
                // 步骤2：加载文件并解析（复用原加载逻辑，自动清理注释/尾随逗号）
                var loadResult = LoadJsonWithCheck(jsonFilePath);
                if (!loadResult.IsSuccess)
                {
                    return new UpdateResult
                    {
                        IsSuccess = false,
                        Message = $"加载文件失败：{loadResult.Message}",
                        TargetPath = fullNodePath
                    };
                }
                rootNode = loadResult.RootNode;

                // 步骤3：定位目标节点及父节点
                // 3.1 先找目标节点
                var targetNode = rootNode.SelectToken(fullNodePath);
                if (targetNode == null)
                {
                    return new UpdateResult
                    {
                        IsSuccess = false,
                        Message = $"未找到目标节点 -> {fullNodePath}",
                        TargetPath = fullNodePath,
                        OldValue = deletedValue
                    };
                }
                // 记录删除前的值（用于结果返回）
                deletedValue = targetNode.ToString(Formatting.None);

                // 3.2 找父节点（区分根节点和非根节点）
                JToken parentNode = targetNode.Parent;
                if (parentNode == null)
                {
                    // 特殊场景：目标节点是根节点（仅当JSON为单一值类型时可能出现，如 {"a":1} 的根是对象，不会触发此场景）
                    return new UpdateResult
                    {
                        IsSuccess = false,
                        Message = "无法删除根节点（删除后JSON将为空）",
                        TargetPath = fullNodePath,
                        OldValue = deletedValue
                    };
                }

                // 步骤4：执行删除（根据父节点类型适配删除逻辑）
                bool isDeleted = false;
                switch (parentNode.Type)
                {
                    // 父节点是对象：按属性名删除
                    case JTokenType.Object:
                        JObject parentObj = (JObject)parentNode;
                        // 从对象的属性中找到目标节点的键名（避免路径解析错误）
                        string targetPropName = targetNode.Path.Split('.').Last();
                        isDeleted = parentObj.Remove(targetPropName);
                        break;

                    // 父节点是数组：按索引删除
                    case JTokenType.Array:
                        JArray parentArr = (JArray)parentNode;
                        // 直接从数组中移除目标节点
                        isDeleted = parentArr.Remove(targetNode);
                        break;

                    // 其他类型（如值类型）：无法删除子节点
                    default:
                        return new UpdateResult
                        {
                            IsSuccess = false,
                            Message = $"父节点类型不支持删除子节点 -> {GetNodeType(parentNode)}",
                            TargetPath = fullNodePath,
                            OldValue = deletedValue
                        };
                }

                if (!isDeleted)
                {
                    return new UpdateResult
                    {
                        IsSuccess = false,
                        Message = "节点定位成功，但删除操作执行失败",
                        TargetPath = fullNodePath,
                        OldValue = deletedValue
                    };
                }

                // 步骤5：保存文件并校验结果（复用原保存/校验逻辑，确保文件安全）
                var saveResult = SaveJsonWithCheck(jsonFilePath, rootNode);
                if (!saveResult.IsSuccess)
                {
                    return new UpdateResult
                    {
                        IsSuccess = false,
                        Message = $"删除失败：{saveResult.Message}",
                        TargetPath = fullNodePath,
                        OldValue = deletedValue
                    };
                }

                // 校验：删除后节点应不存在
                var verifyResult = VerifyNodeDeleted(jsonFilePath, fullNodePath);
                if (!verifyResult.IsSuccess)
                {
                    return new UpdateResult
                    {
                        IsSuccess = false,
                        Message = $"删除失败：{verifyResult.Message}",
                        TargetPath = fullNodePath,
                        OldValue = deletedValue
                    };
                }

                // 成功返回
                return new UpdateResult
                {
                    IsSuccess = true,
                    Message = "节点删除成功并保存",
                    TargetPath = fullNodePath,
                    OldValue = deletedValue
                };
            }
            catch (JsonReaderException ex)
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = $"JSON格式错误：{ex.Message}",
                    TargetPath = fullNodePath,
                    OldValue = deletedValue
                };
            }
            catch (Exception ex)
            {
                return new UpdateResult
                {
                    IsSuccess = false,
                    Message = $"删除节点失败：{ex.Message}",
                    TargetPath = fullNodePath,
                    OldValue = deletedValue
                };
            }
        }
        /// <summary>
        /// 校验节点是否已被删除（重新读取文件确认）
        /// </summary>
        private static (bool IsSuccess, string Message) VerifyNodeDeleted(string jsonFilePath, string targetPath)
        {
            try
            {
                // 重新加载文件（复用清理逻辑）
                var loadResult = LoadJsonWithCheck(jsonFilePath);
                if (!loadResult.IsSuccess)
                {
                    return (false, $"重新加载文件失败：{loadResult.Message}");
                }

                // 检查目标节点是否存在（删除成功则应返回null）
                var targetNode = loadResult.RootNode.SelectToken(targetPath);
                if (targetNode != null)
                {
                    return (false, "校验失败：目标节点仍存在（可能删除未生效）");
                }

                return (true, "校验通过：目标节点已成功删除");
            }
            catch (Exception ex)
            {
                return (false, $"校验删除结果失败 -> {ex.Message}");
            }
        }
    }
}